This document aims at exploring two datasets, one in 2016 on 6 individuals and another one in 2018 on 4 individuals. For that purpose, we need first to load the weanlingNES package to load data.

# load library
library(weanlingNES)

# load data
data("data_nes", package = "weanlingNES")

1 2016-individuals

Let’s have a look at what’s inside data_nes$data_2016:

# list structure
str(data_nes$year_2016, max.level = 1, give.attr = F, no.list = T)
##  $ ind_3449:Classes 'data.table' and 'data.frame':   384 obs. of  23 variables:
##  $ ind_3450:Classes 'data.table' and 'data.frame':   253 obs. of  23 variables:
##  $ ind_3456:Classes 'data.table' and 'data.frame':   253 obs. of  23 variables:
##  $ ind_3457:Classes 'data.table' and 'data.frame':   253 obs. of  23 variables:
##  $ ind_3460:Classes 'data.table' and 'data.frame':   253 obs. of  23 variables:
##  $ ind_3463:Classes 'data.table' and 'data.frame':   213 obs. of  23 variables:

A list of 6 data.frames, one for each seal

For convenience, we aggregate all 6 individuals into one dataset.

# combine all individuals
data_2016 = rbindlist(data_nes$year_2016, use.name = TRUE, idcol = TRUE)

# display
DT::datatable(data_2016[sample.int(.N,100),],options=list(scrollX=T))
Table 1.1: Sample of 100 random rows from data_2016

1.1 Summary

# raw_data
data_2016[, .(
  nb_days_recorded = uniqueN(as.Date(date)),
  max_depth = max(maxpress_dbars),
  sst_mean = mean(sst2_c),
  sst_sd = sd(sst2_c)
), by =.id] %>%
  sable(caption="Summary diving information relative to each 2016 individual", 
        digits=2)
Table 1.2: Summary diving information relative to each 2016 individual
.id nb_days_recorded max_depth sst_mean sst_sd
ind_3449 384 1118.81 26.54 129.91
ind_3450 253 954.81 130.29 367.69
ind_3456 253 697.63 125.24 360.39
ind_3457 253 572.94 135.56 374.71
ind_3460 253 832.25 65.24 249.12
ind_3463 213 648.81 212.19 462.88

Well, it seems that sst is a bit odd. Let’s have a look at its distribution.

ggplot(data_2016, aes(x = sst2_c, fill = .id)) +
  geom_histogram(show.legend = FALSE) +
  facet_wrap(.id ~ .) +
  theme_jjo()
Distribution of raw `sst2` for the four individuals in 2016

Figure 1.1: Distribution of raw sst2 for the four individuals in 2016

Let’s remove any data with a sst2_c > 500.

data_2016_filter = data_2016[sst2_c < 500, ]
ggplot(data_2016_filter, aes(x = sst2_c, fill = .id)) +
  geom_histogram(show.legend = FALSE) +
  facet_wrap(.id ~ .) +
  theme_jjo()
Distribution of filtered `sst2` for the four individuals in 2016

Figure 1.2: Distribution of filtered sst2 for the four individuals in 2016

Well, that seems to be much better! In the process of filtering out odd values, we removed 116 rows this way:

# nbrow removed
data_2016[sst2_c>500,.(nb_row_removed = .N),by=.id] %>%
  sable(caption = "# of rows removed by 2016-individuals")
Table 1.3: # of rows removed by 2016-individuals
.id nb_row_removed
ind_3449 4
ind_3450 23
ind_3456 22
ind_3457 24
ind_3460 10
ind_3463 33
# max depth
ggplot(data_2016,
       aes(y = -maxpress_dbars, x=as.Date(date), col=.id)) +
  geom_path(show.legend = FALSE) +
  geom_point(data = data_2016[sst2_c>500,], col="black") +
  scale_x_date(date_labels = "%m/%Y") +
  labs(y="Pressure (dbar)", x="Date") +
  facet_wrap(.id ~ .) +
  theme_jjo() +
  theme(axis.text.x = element_text(angle = 45, hjust=1))
Where and when the `sst2` outliers occured

Figure 1.3: Where and when the sst2 outliers occured

Well this latter plot highlights several points:

  • most of the outliers occur while animals spend the whole day at the surface (or on the ground), probably resting, so essentially at the beginning and the end of each track
  • we can already see that ind_3449 seems to have return ashore twice during his track

Let’s see if we can double check that, using a map.

# interactive map
leaflet() %>%
  setView(lng = -122, lat = 38, zoom = 2) %>%
  addTiles() %>%
  addPolylines(lat = data_2016[.id == "ind_3449", latitude_degs],
               lng = data_2016[.id == "ind_3449", longitude_degs],
               weight = 2) %>%
  addCircleMarkers(lat = data_2016[.id == "ind_3449" & sst2_c>500, latitude_degs],
                   lng = data_2016[.id == "ind_3449" & sst2_c>500, longitude_degs],
                   radius = 3,
                   stroke=FALSE,
                   color="red",
                   fillOpacity=1)

Figure 1.4: It is supposed to be the track of ind_3449… (red dots are the location of removed rows)

… these coordinates seem weird !

# summary of the coordinates by individuals
data_2016[, .(.id, longitude_degs, latitude_degs)] %>%
  tbl_summary(by = .id) %>%
  modify_caption("Summary of `longitude_degree` and `latitude_degree`")
Table 1.4: Summary of longitude_degree and latitude_degree
Characteristic ind_3449, N = 3841 ind_3450, N = 2531 ind_3456, N = 2531 ind_3457, N = 2531 ind_3460, N = 2531 ind_3463, N = 2131
longitude_degs -119 (-132, -69) -124 (-144, -99) -112 (-134, -6) -122 (-132, -97) -122 (-144, -85) -121 (-134, -93)
latitude_degs 39 (-67, 68) 60 (-63, 68) 56 (-63, 68) 44 (-63, 68) 59 (-63, 68) 63 (42, 72)

1 Median (IQR)

# distribution coordinates
ggplot(
  data = melt(data_2016[, .(Longitude = longitude_degs, 
                            Latitude = latitude_degs, 
                            .id)], id.vars =
                ".id", value.name = "Coordinate"),
  aes(x = Coordinate, fill = .id)
) +
  geom_histogram(show.legend = F) +
  facet_grid(variable ~ .id) +
  theme_jjo()
Distribution of coordinates per seal

Figure 1.5: Distribution of coordinates per seal

There is definitely something wrong with these coordinates (five seals would have crossed the equator…), but the representation of the track can also be improved! Here are the some points to explore:

  • For longitude a part of the data seems to have a wrong sign, resulting in these distribution, that appear to be cut off
  • For latitude, well this is ensure but maybe the same problem occurs

Let’s try to play on coordinates’ sign to see if we can display something that makes more sense.

# interactive map
leaflet() %>%
  setView(lng = -122, lat = 50, zoom = 3) %>%
  addTiles() %>%
  addPolylines(lat = data_2016[.id == "ind_3449", abs(latitude_degs)],
               lng = data_2016[.id == "ind_3449", -abs(longitude_degs)],
               weight = 2)

Figure 1.6: An attempt to display the ind_3449’s track

I’ll better ask Roxanne!

1.2 Missing values

# build dataset to check for missing values
dataPlot = melt(data_2016_filter[, .(.id, is.na(.SD)), .SDcol = -c(".id",
                                                            "rec#",
                                                            "date",
                                                            "time")])
# add the id of rows
dataPlot[, id_row := c(1:.N), by = c("variable",".id")]

# plot
ggplot(dataPlot, aes(x = variable, y = id_row, fill = value)) +
  geom_tile() +
  labs(x = "Attributes", y = "Rows") +
  scale_fill_manual(values = c("white", "black"),
                    labels = c("Real", "Missing")) +
  facet_wrap(.id ~ ., scales = "free_y") +
  theme_jjo() +
  theme(
    legend.position = "top",
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.key = element_rect(colour = "black")
  )
Check for missing value in 2016-individuals

Figure 1.7: Check for missing value in 2016-individuals

2 2018-individuals

Let’s have a look at what’s inside data_nes$data_2018:

# list structure
str(data_nes$year_2018, max.level = 1, give.attr = F, no.list = T)
##  $ ind_2018070:Classes 'data.table' and 'data.frame':    22393 obs. of  42 variables:
##  $ ind_2018072:Classes 'data.table' and 'data.frame':    29921 obs. of  42 variables:
##  $ ind_2018074:Classes 'data.table' and 'data.frame':    38608 obs. of  42 variables:
##  $ ind_2018080:Classes 'data.table' and 'data.frame':    19028 obs. of  42 variables:

A list of 4 data.frames, one for each seal

For convenience, we aggregate all 4 individuals into one dataset.

# combine all individuals
data_2018 = rbindlist(data_nes$year_2018, use.name = TRUE, idcol = TRUE)

# display
DT::datatable(data_2018[sample.int(.N,100),],options=list(scrollX=T))
Table 1.1: Sample of 100 random rows from data_2018

2.1 Summary

# raw_data
data_2018[, .(
  nb_days_recorded = uniqueN(as.Date(date)),
  nb_dives = .N,
  maxdepth_mean = mean(maxdepth),
  dduration_mean = mean(dduration),
  botttime_mean = mean(botttime),
  pdi_mean = mean(pdi, na.rm=T)
), by =.id] %>%
  sable(caption="Summary diving information relative to each 2018 individual", 
        digits=2)
Table 2.1: Summary diving information relative to each 2018 individual
.id nb_days_recorded nb_dives maxdepth_mean dduration_mean botttime_mean pdi_mean
ind_2018070 232 22393 305.52 783.27 243.22 109.55
ind_2018072 341 29921 357.86 876.96 278.02 104.90
ind_2018074 372 38608 250.67 686.25 291.89 302.77
ind_2018080 215 19028 296.50 867.69 339.90 103.51

Very nice dataset :)

2.2 Some explanatory plots

2.2.1 Missing values

# build dataset to check for missing values
dataPlot = melt(data_2018[, .(.id, is.na(.SD)), .SDcol = -c(".id",
                                                            "divenumber",
                                                            "year",
                                                            "month",
                                                            "day",
                                                            "hour",
                                                            "min",
                                                            "sec",
                                                            "juldate",
                                                            "divetype",
                                                            "date")])
# add the id of rows
dataPlot[, id_row := c(1:.N), by = c("variable",".id")]

# plot
ggplot(dataPlot, aes(x = variable, y = id_row, fill = value)) +
  geom_tile() +
  labs(x = "Attributes", y = "Rows") +
  scale_fill_manual(values = c("white", "black"),
                    labels = c("Real", "Missing")) +
  facet_wrap(.id ~ ., scales = "free_y") +
  theme_jjo() +
  theme(
    legend.position = "top",
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.key = element_rect(colour = "black")
  )
Check for missing value in 2018-individuals

Figure 2.1: Check for missing value in 2018-individuals

So far so good, only few variables seems to have missing values:

# table with percent
table_inter = data_2018[, lapply(.SD, function(x) {
  round(length(x[is.na(x)]) * 100 / length(x), 1)
}), .SDcol = -c(
  ".id",
  "divenumber",
  "year",
  "month",
  "day",
  "hour",
  "min",
  "sec",
  "juldate",
  "divetype",
  "date"
)]

# find which are different from 0
cond_inter = sapply(table_inter,function(x){x==0})

# display the percentages that are over 0
table_inter[,which(cond_inter) := NULL] %>%
  sable(caption="Percentage of missing values per columns having missing values!")%>% 
  scroll_box(width = "100%")
Table 2.2: Percentage of missing values per columns having missing values!
lightatsurf lattenuation euphoticdepth thermoclinedepth driftrate benthicdivevertrate cornerindex foragingindex verticalspeed90perc verticalspeed95perc
26.3 89 62.6 1.3 0.5 22.7 75.8 0.5 0.1 0.1

2.2.2 Outliers

Ok, let’s have a look at all the data. But first, we have to remove outliers. Some of them are quiet easy to spot looking at the distribution of dive duration:

Before

ggplot(data_2018[,.SD][,state:="Before"], 
       aes(x=dduration, fill = .id))+
  geom_histogram(show.legend = FALSE)+
  geom_vline(xintercept = 3000, linetype = "longdash") +
  facet_grid(state~.id,
             scales="free")+
  labs(y="# of dives", x="Dive duration (s)")+
  theme_jjo()
Distribution of `dduration` for each seal. The dashed line highlight the "subjective" threshold used to remove outliers (3000 sec)

Figure 2.2: Distribution of dduration for each seal. The dashed line highlight the “subjective” threshold used to remove outliers (3000 sec)

After

ggplot(data_2018[dduration<3000,][][,state:="After"], 
       aes(x=dduration, fill = .id))+
  geom_histogram(show.legend = FALSE)+
  geom_vline(xintercept = 3000, linetype = "longdash") +
  facet_grid(state~.id,
             scales="free")+
  labs(x="# of dives", y="Dive duration (s)")+
  theme_jjo()
Same distribution of `dduration` for each seal but after removing any `dduration` > 3000 sec. The dashed line highlight the "subjective" threshold used to remove outliers

Figure 2.3: Same distribution of dduration for each seal but after removing any dduration > 3000 sec. The dashed line highlight the “subjective” threshold used to remove outliers

It seems muche better, so let’s remove any rows with dduration > 3000 sec.

# filter data
data_2018_filter = data_2018[dduration < 3000, ]

# nbrow removed
data_2018[dduration>= 3000,.(nb_row_removed = .N),by=.id] %>%
  sable(caption = "# of rows removed by 2018-individuals")
Table 2.3: # of rows removed by 2018-individuals
.id nb_row_removed
ind_2018070 3
ind_2018072 1
ind_2018074 33

2.2.3 All Variables

names_display = names(data_2018_filter[, -c(
  ".id",
  "date",
  "divenumber",
  "year",
  "month",
  "day",
  "hour",
  "min",
  "sec",
  "juldate",
  "divetype",
  "euphoticdepth",
  "thermoclinedepth",
  "day_departure"
)])
for (i in names_display) {
  cat('####', i, '{-} \n')
  if (i == "maxdepth") {
    print(
      ggplot() +
        geom_point(
          data = data_2018_filter[, .(.id,
                                                          date,
                                                          thermoclinedepth)],
          aes(
            x = as.Date(date),
            y = -thermoclinedepth,
            colour = "Thermocline (m)"
          ),
          
          alpha = .2,
          size = .5
        ) +
        geom_point(
          data = data_2018_filter[, .(.id,
                                                          date,
                                                          euphoticdepth)],
          aes(
            x = as.Date(date),
            y = -euphoticdepth,
            colour = "Euphotic (m)"
          ),
          alpha = .2,
          size = .5
        ) +
        scale_colour_manual(
          values = c("Thermocline (m)" = 'red',
                     "Euphotic (m)" = "black"),
          name = "Zone"
        ) +
        new_scale_color() +
        geom_point(
          data = melt(data_2018_filter[, .(.id, date, get(i))], id.vars = c(".id", "date")),
          aes(
            x = as.Date(date),
            y = -value,
            col = .id
          ),
          alpha = 1 / 10,
          size = .5,
          show.legend = FALSE
        ) +
        facet_wrap(. ~ .id, scales = "free") +
        scale_x_date(date_labels = "%m/%Y") +
        labs(x = "Date", y = "Maximum Depth (m)") +
        theme_jjo() +
        theme(axis.text.x = element_text(angle = 45, hjust = 1),
              legend.position="bottom")
    )
    cat("<blockquote> Considering `ind_2018074` has slightly different values than other individuals for the thermocline depth, it would be interesting to see where the animal went. </blockquote>")
  } else {
    print(
      ggplot(
        data = melt(data_2018_filter[, .(.id, date, get(i))], id.vars = c(".id", "date")),
        aes(
          x = as.Date(date),
          y = value,
          col = .id
        )
      ) +
        geom_point(
          show.legend = FALSE,
          alpha = 1 / 10,
          size = .5
        ) +
        facet_wrap(. ~ .id, scales = "free") +
        scale_x_date(date_labels = "%m/%Y") +
        labs(x = "Date", y = i) +
        theme_jjo() +
        theme(axis.text.x = element_text(angle = 45, hjust = 1))
    )
  }
  
  cat(' \n \n')
}

maxdepth

Considering ind_2018074 has slightly different values than other individuals for the thermocline depth, it would be interesting to see where the animal went.

dduration

botttime

desctime

descrate

asctime

ascrate

pdi

dwigglesdesc

dwigglesbott

dwigglesasc

totvertdistbot

bottrange

efficiency

idz

lightatbott

lwiggles

lightatsurf

lattenuation

tempatsurf

tempatbott

driftdiveindex

driftrate

benthicdiveindex

benthicdivevertrate

cornerindex

foragingindex

verticalspeed90perc

verticalspeed95perc

Few questions, that I should look into it:

  • is the bimodal distribution of dduration, desctime due to nycthemeral migration?
  • is the bimodal distribution of descrate (especially for ind2018070 and ind_2018072) due to drift dive?
  • is lightatbott could be used to identify bioluminescence, cause it seems there is a lot going on at the bottom?
  • are the variations observed for lightatsurf is due to moon cycle?
  • not sure why is there a bimodal distribution of tempatbott!
  • drifrate that one is awesome, since we can clearly see a pattern of how driftrate (and so buoyancy) change according time, but it is noisy due to negative and positive values occurring even at the beginning of the trip. I guess you measure driftrate also in ascent phases? That figure illustrate something we also found on Southern elephant seals, that drift rate varies at the descent, but rarely at the ascent. If I well remember, to maintain a constant drift rate in ascent phase during the whole trip, Southern elephant adjust their pitch (diving angle)
  • the bimodal distribution of verticalspeed90 and verticalspeed95 should be due to drift dive.

2.2.4 All Variables during the first month

for (i in names_display) {
  cat('####', i, '{-} \n')
  if (i == "maxdepth") {
    print(
      ggplot() +
        geom_point(
          data = data_2018_filter[day_departure < 32, .(.id,
                                                          day_departure,
                                                          thermoclinedepth)],
          aes(
            x = day_departure,
            y = -thermoclinedepth,
            colour = "Thermocline (m)",
            group = day_departure
          ),
          
          alpha = .2,
          size = .5
        ) +
        geom_point(
          data = data_2018_filter[day_departure < 32, .(.id,
                                                          day_departure,
                                                          euphoticdepth)],
          aes(
            x = day_departure,
            y = -euphoticdepth,
            colour = "Euphotic (m)",
            group = day_departure
          ),
          alpha = .2,
          size = .5
        ) +
        scale_colour_manual(
          values = c("Thermocline (m)" = 'red',
                     "Euphotic (m)" = "black"),
          name = "Zone"
        ) +
        new_scale_color() +
        geom_boxplot(
          data = melt(data_2018_filter[day_departure < 32, .(.id, day_departure, get(i))], id.vars = c(".id", "day_departure")),
          aes(
            x = day_departure,
            y = -value,
            col = .id,
            group = day_departure
          ),
          alpha = 1 / 10,
          size = .5,
          show.legend = FALSE
        ) +
        facet_wrap(. ~ .id, scales = "free") +
        labs(x = "# days since departure", y = "Maximum Depth (m)") +
        theme_jjo() +
        theme(legend.position="bottom")
    )
  } else {
    print(
      ggplot(
        data = melt(data_2018_filter[day_departure < 32, .(.id, day_departure, get(i))], id.vars = c(".id", "day_departure")),
        aes(
          x = day_departure,
          y = value,
          color = .id,
          group = day_departure
        )
      ) +
        geom_boxplot(
          show.legend = FALSE,
          alpha = 1 / 10,
          size = .5
        ) +
        facet_wrap(. ~ .id, scales = "free") +
        labs(x = "# days since departure", y = i) +
        theme_jjo()
    )
  }
  
  cat(' \n \n')
}

maxdepth

dduration

botttime

desctime

descrate

asctime

ascrate

pdi

dwigglesdesc

dwigglesbott

dwigglesasc

totvertdistbot

bottrange

efficiency

idz

lightatbott

lwiggles

lightatsurf

lattenuation

tempatsurf

tempatbott

driftdiveindex

driftrate

benthicdiveindex

benthicdivevertrate

cornerindex

foragingindex

verticalspeed90perc

verticalspeed95perc

2.2.5 Correlation

Can we find nice correlation?

# compute correlation
corr_2018 = round(cor(data_2018_filter[, names_display, with = F], 
                      use = "pairwise.complete.obs"), 1)

# replace NA value by 0
corr_2018[is.na(corr_2018)] = 0

# compute p_values
corr_p_2018 = cor_pmat(data_2018_filter[, names_display, with = F])

# replace NA value by 0
corr_p_2018[is.na(corr_p_2018)] = 1

# display
ggcorrplot(
  corr_2018,
  p.mat = corr_p_2018,
  hc.order = TRUE,
  method = "circle",
  type = "lower",
  ggtheme = theme_jjo(),
  sig.level = 0.05,
  colors =  c("#00AFBB", "#E7B800", "#FC4E07")
)
Correlation matrix (crosses indicate non significant correlation)

Figure 2.4: Correlation matrix (crosses indicate non significant correlation)

Another way to see it:

# flatten correlation matrix
cor_result_2018 = flat_cor_mat(corr_2018, corr_p_2018)

# keep only the one above .7
cor_result_2018[cor>=.7,][order(-abs(cor))] %>%
  sable(caption="Pairwise correlation above 0.75 and associated p-values")
Table 2.4: Pairwise correlation above 0.75 and associated p-values
row column cor p
verticalspeed90perc verticalspeed95perc 1.0 0
maxdepth asctime 0.8 0
botttime efficiency 0.8 0
dwigglesbott foragingindex 0.8 0
maxdepth dduration 0.7 0
maxdepth desctime 0.7 0
dduration desctime 0.7 0
dduration asctime 0.7 0
totvertdistbot bottrange 0.7 0
totvertdistbot verticalspeed90perc 0.7 0
totvertdistbot verticalspeed95perc 0.7 0

I guess nothing unexpected here, I’ll have to check with Patrick about the efficiency ;)

2.3 Dive Type

# dataset to plot proportional area plot
data_2018_filter[, sum_id := .N, by = .(.id, day_departure)][, sum_id_days := .N, by = .(.id, day_departure, divetype)][, prop := sum_id_days /
                                                                                                                          sum_id]
dataPlot = unique(data_2018_filter[, .(prop, .id, divetype, day_departure)])

# area plot
ggplot(dataPlot, aes(
  x = as.numeric(day_departure),
  y = prop,
  fill = as.character(divetype)
)) +
  geom_area(alpha = 0.6 , size = 1) +
  facet_wrap(.id ~ ., scales = "free") +
  theme_jjo() +
  theme(legend.position="bottom") +
  labs(x="# of days since departure", y="Proportion of dives", fill = "Dive types")
Proportion dive types

Figure 2.5: Proportion dive types

2.4 Dive duration vs. Maximum depth

2.4.1 Colored by ID

# plot
ggplot(data = data_2018_filter, aes(y = dduration, x = maxdepth, col = .id)) +
  geom_point(size = .5, alpha = .1, show.legend = FALSE) +
  facet_wrap(.id ~ .) +
  labs(x="Maximum depth (m)", y="Dive duration (s)")+
  theme_jjo()
Dive duration vs. Maximum Depth colored 2018-individuals

Figure 2.6: Dive duration vs. Maximum Depth colored 2018-individuals

2.4.2 Colored by Dive Type

# plot
ggplot(data = data_2018_filter, aes(y = dduration, x = maxdepth, col = divetype)) +
  geom_point(size = .5, alpha = .1) +
  facet_wrap(.id ~ .) +
  guides(colour = guide_legend(override.aes = list(size = 5, alpha = 1))) +
  labs(x="Maximum depth (m)", y="Dive duration (s)")+
  theme_jjo() +
  theme(legend.position="bottom")
Dive duration vs. Maximum Depth colored by Dive Type

Figure 2.7: Dive duration vs. Maximum Depth colored by Dive Type

2.4.3 Colored by # days since departure

# plot
ggplot(data = data_2018_filter[,prop_track := (day_departure*100)/max(day_departure),by=.id], aes(y = dduration, x = maxdepth, col = prop_track)) +
  geom_point(size = .5, alpha = .1) +
  facet_wrap(.id ~ .) +
  labs(x="Maximum depth (m)", y="Dive duration (s)", col="Proportion of completed track (%)")+
  scale_color_continuous(type = "viridis")+
  theme_jjo() +
  theme(legend.position="bottom")
Dive duration vs. Maximum Depth colored by # days since departure

Figure 2.8: Dive duration vs. Maximum Depth colored by # days since departure

There seems to be a patch for high depths (especially visible for ind2018070), but I don’t know what it could be linked to…

2.5 Drift Rate

Not sure about these graphs, especialy if driftrate is calculated during both ascent and descent phases.

# plot
ggplot(data_2018_filter[,.(driftrate=median(driftrate,na.rm=T),
                           botttime=median(botttime,na.rm=T),
                           maxdepth=median(maxdepth,na.rm=T),
                           dduration=median(dduration,na.rm=T)), by=.(.id,day_departure)],
       aes(x=botttime, y=driftrate, col=.id))+
  geom_point(size=.5,alpha=.5)+
  geom_smooth(method="lm")+
  guides(color=FALSE)+
  facet_wrap(.id~.)+
  scale_x_continuous(limits = c(0,700))+
  labs(x = "Daily median Bottom time (s)", y = "Daily median drift rate (m.s-1)")+
  theme_jjo()
Drift rate vs. Bottom time

Figure 2.9: Drift rate vs. Bottom time

# plot
ggplot(data_2018_filter[,.(driftrate=median(driftrate,na.rm=T),
                           botttime=median(botttime,na.rm=T),
                           maxdepth=median(maxdepth,na.rm=T),
                           dduration=median(dduration,na.rm=T)), by=.(.id,day_departure)],
       aes(x=maxdepth, y=driftrate, col=.id))+
  geom_point(size=.5,alpha=.5)+
  geom_smooth(method="lm")+
  guides(color=FALSE)+
  facet_wrap(.id~.)+
  labs(x = "Daily median Maximum depth (m)", y = "Daily median drift rate (m.s-1)")+
  theme_jjo()
Drift rate vs. Maximum depth

Figure 2.10: Drift rate vs. Maximum depth

# plot
ggplot(data_2018_filter[,.(driftrate=median(driftrate,na.rm=T),
                           botttime=median(botttime,na.rm=T),
                           maxdepth=median(maxdepth,na.rm=T),
                           dduration=median(dduration,na.rm=T)), by=.(.id,day_departure)],
       aes(x=dduration, y=driftrate, col=.id))+
  geom_point(size=.5,alpha=.5)+
  geom_smooth(method="lm")+
  guides(color=FALSE)+
  facet_wrap(.id~.)+
  labs(x = "Daily median Dive duration (s)", y = "Daily median drift rate (m.s-1)")+
  theme_jjo()
Drift rate vs. Dive duration

Figure 2.11: Drift rate vs. Dive duration

LS0tCnRpdGxlOiAiRGF0YSBFeHBsb3JhdGlvbiIKYXV0aG9yOiAiSm9mZnJleSBKT1VNQUEiCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgZm9ybWF0ID0gJyVkICVCICVZJylgIgpvdXRwdXQ6CiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOgogICAgY3NzOiBjb3Ntb19jdXN0b20uY3NzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBkZl9wcmludDogZGVmYXVsdAogICAgZmlnX2NhcHRpb246IHllcwogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHllcwogICAgICBzbW9vdGhfc2Nyb2xsOiBubwp2aWduZXR0ZTogPgogICVcVmlnbmV0dGVJbmRleEVudHJ5e0RhdGEgRXhwbG9yYXRpb259CiAgJVxWaWduZXR0ZUVuZ2luZXtrbml0cjo6cm1hcmtkb3dufQogICVcVmlnbmV0dGVFbmNvZGluZ3tVVEYtOH0KLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBjb21tYW5kIHRvIGJ1aWxkIHBhY2thZ2Ugd2l0aG91dCBnZXR0aW5nIHZpZ25ldHRlIGVycm9yCiMgaHR0cHM6Ly9naXRodWIuY29tL3JzdHVkaW8vcmVudi9pc3N1ZXMvODMzCmRldnRvb2xzOjpjaGVjayhidWlsZF9hcmdzPWMoIi0tbm8tYnVpbGQtdmlnbmV0dGVzIikpCgojIGdsb2JhbCBvcHRpb24gcmVsYXRpdmUgdG8gcm1hcmtkb3duCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICdjZW50ZXInLAogICAgICAgICAgICAgICAgICAgICAgb3V0LndpZHRoID0gIjEwMCUiLAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgd2FybmluZz1GQUxTRSkKCiMgbGlicmFyeQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KGxlYWZsZXQpIApsaWJyYXJ5KGd0c3VtbWFyeSkgI2h0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9ndHN1bW1hcnkvdmlnbmV0dGVzL3RibF9zdW1tYXJ5Lmh0bWwKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShnZ2NvcnJwbG90KQpsaWJyYXJ5KGdnbmV3c2NhbGUpCgojIGRlZmluZSBteSBvd24gdGFibGUgZm9ybWF0OiBodHRwczovL2dpdGh1Yi5jb20vaGFvemh1MjMzL2thYmxlRXh0cmEvaXNzdWVzLzM3NApzYWJsZSA8LSBmdW5jdGlvbih4LCBlc2NhcGUgPSBULCAuLi4pIHsKICBrbml0cjo6a2FibGUoeCwgZXNjYXBlID0gZXNjYXBlLCAuLi4pICU+JQogICAga2FibGVfc3R5bGluZygKICAgICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgInJlc3BvbnNpdmUiKSwKICAgICAgZnVsbF93aWR0aCA9IEYKICAgICkKfQoKIyB0aGVtZSBnZ3Bsb3QKIyBiYXNlZDogaHR0cHM6Ly9iZW5qYW1pbmxvdWlzLXN0YXQuZnIvZW4vYmxvZy8yMDIwLTA1LTIxLWFzdHVjZXMtZ2dwbG90LXJtYXJrZG93bi8KdGhlbWVfampvIDwtIGZ1bmN0aW9uKGJhc2Vfc2l6ZSA9IDEyKSB7CiAgdGhlbWVfYncoYmFzZV9zaXplID0gYmFzZV9zaXplKSAlK3JlcGxhY2UlCiAgICB0aGVtZSgKICAgICAgIyB0aGUgd2hvbGUgZmlndXJlCiAgICAgICNwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMSksIGZhY2UgPSAiYm9sZCIsIG1hcmdpbiA9IG1hcmdpbigwLDAsNSwwKSwgaGp1c3QgPSAwKSwKICAgICAgIyBmaWd1cmUgYXJlYQogICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICMgYXhlcwogICAgICAjYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuODUpLCBmYWNlID0gImJvbGQiKSwKICAgICAgI2F4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNzApLCBmYWNlID0gImJvbGQiKSwKICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG9yID0gImJsYWNrIiwgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImxpbmVzIiksIHR5cGUgPSAiY2xvc2VkIikpLAogICAgICAjIGxlZ2VuZAogICAgICAjIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuODUpLCBmYWNlID0gImJvbGQiKSwKICAgICAgIyBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNzApLCBmYWNlID0gImJvbGQiKSwKICAgICAgIyBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksCiAgICAgICMgbGVnZW5kLmtleS5zaXplID0gdW5pdCgxLjUsICJsaW5lcyIpLAogICAgICAjIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksCiAgICAgICMgTGVzIMOpdGlxdWV0dGVzIGRhbnMgbGUgY2FzIGQndW4gZmFjZXR0aW5nCiAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjODg4ODg4IiwgY29sb3IgPSAiIzg4ODg4OCIpLAogICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC44NSksIGZhY2UgPSAiYm9sZCIsIGNvbG9yID0gIndoaXRlIiwgbWFyZ2luID0gbWFyZ2luKDUsMCw1LDApKQogICAgKQp9CmBgYAoKVGhpcyBkb2N1bWVudCBhaW1zIGF0IGV4cGxvcmluZyB0d28gZGF0YXNldHMsIG9uZSBpbiAyMDE2IG9uIDYgaW5kaXZpZHVhbHMgYW5kIGFub3RoZXIgb25lIGluIDIwMTggb24gNCBpbmRpdmlkdWFscy4gRm9yIHRoYXQgcHVycG9zZSwgd2UgbmVlZCBmaXJzdCB0byBsb2FkIHRoZSBgd2VhbmxpbmdORVNgIHBhY2thZ2UgdG8gbG9hZCBkYXRhLgoKYGBge3J9CiMgbG9hZCBsaWJyYXJ5CmxpYnJhcnkod2VhbmxpbmdORVMpCgojIGxvYWQgZGF0YQpkYXRhKCJkYXRhX25lcyIsIHBhY2thZ2UgPSAid2VhbmxpbmdORVMiKQpgYGAKCgojIDIwMTYtaW5kaXZpZHVhbHMgCgpMZXQncyBoYXZlIGEgbG9vayBhdCB3aGF0J3MgaW5zaWRlIGBkYXRhX25lcyRkYXRhXzIwMTZgOgoKYGBge3J9CiMgbGlzdCBzdHJ1Y3R1cmUKc3RyKGRhdGFfbmVzJHllYXJfMjAxNiwgbWF4LmxldmVsID0gMSwgZ2l2ZS5hdHRyID0gRiwgbm8ubGlzdCA9IFQpCmBgYAoKPiBBIGxpc3Qgb2YgYHIgbGVuZ3RoKGRhdGFfbmVzJHllYXJfMjAxNilgIGBkYXRhLmZyYW1lc2AsIG9uZSBmb3IgZWFjaCBzZWFsCgpGb3IgY29udmVuaWVuY2UsIHdlIGFnZ3JlZ2F0ZSBhbGwgYHIgbGVuZ3RoKGRhdGFfbmVzJHllYXJfMjAxNilgIGluZGl2aWR1YWxzIGludG8gb25lIGRhdGFzZXQuCgpgYGB7ciwgZXZhbD1GQUxTRX0KIyBjb21iaW5lIGFsbCBpbmRpdmlkdWFscwpkYXRhXzIwMTYgPSByYmluZGxpc3QoZGF0YV9uZXMkeWVhcl8yMDE2LCB1c2UubmFtZSA9IFRSVUUsIGlkY29sID0gVFJVRSkKCiMgZGlzcGxheQpEVDo6ZGF0YXRhYmxlKGRhdGFfMjAxNltzYW1wbGUuaW50KC5OLDEwMCksXSxvcHRpb25zPWxpc3Qoc2Nyb2xsWD1UKSkKYGBgCmBgYHtyLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30KIyBjb21iaW5lIGFsbCBpbmRpdmlkdWFscwpkYXRhXzIwMTYgPSByYmluZGxpc3QoZGF0YV9uZXMkeWVhcl8yMDE2LCB1c2UubmFtZSA9IFRSVUUsIGlkY29sID0gVFJVRSkKCiMgdGl0bGUKY2F0KCI8dGFibGUgc3R5bGU9J3dpZHRoOiA1MCUnPiIscGFzdGUwKCI8Y2FwdGlvbj4iLCAiKCN0YWI6bXlEVGh0bWx0b29scykiLCAiU2FtcGxlIG9mIDEwMCByYW5kb20gcm93cyBmcm9tIGBkYXRhXzIwMTZgIiwgIjwvY2FwdGlvbj4iKSwiPC90YWJsZT4iLCBzZXAgPSJcbiIpCgojIGRpc3BsYXkKRFQ6OmRhdGF0YWJsZShkYXRhXzIwMTZbc2FtcGxlLmludCguTiwxMDApLF0sb3B0aW9ucz1saXN0KHNjcm9sbFg9VCkpCmBgYAoKIyMgU3VtbWFyeQoKYGBge3J9CiMgcmF3X2RhdGEKZGF0YV8yMDE2WywgLigKICBuYl9kYXlzX3JlY29yZGVkID0gdW5pcXVlTihhcy5EYXRlKGRhdGUpKSwKICBtYXhfZGVwdGggPSBtYXgobWF4cHJlc3NfZGJhcnMpLAogIHNzdF9tZWFuID0gbWVhbihzc3QyX2MpLAogIHNzdF9zZCA9IHNkKHNzdDJfYykKKSwgYnkgPS5pZF0gJT4lCiAgc2FibGUoY2FwdGlvbj0iU3VtbWFyeSBkaXZpbmcgaW5mb3JtYXRpb24gcmVsYXRpdmUgdG8gZWFjaCAyMDE2IGluZGl2aWR1YWwiLCAKICAgICAgICBkaWdpdHM9MikKYGBgCgpXZWxsLCBpdCBzZWVtcyB0aGF0IGBzc3RgIGlzIGEgYml0IG9kZC4gTGV0J3MgaGF2ZSBhIGxvb2sgYXQgaXRzIGRpc3RyaWJ1dGlvbi4KCgpgYGB7ciwgZmlnLmNhcD0iRGlzdHJpYnV0aW9uIG9mIHJhdyBgc3N0MmAgZm9yIHRoZSBmb3VyIGluZGl2aWR1YWxzIGluIDIwMTYifQpnZ3Bsb3QoZGF0YV8yMDE2LCBhZXMoeCA9IHNzdDJfYywgZmlsbCA9IC5pZCkpICsKICBnZW9tX2hpc3RvZ3JhbShzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuKSArCiAgdGhlbWVfampvKCkKYGBgCgpMZXQncyByZW1vdmUgYW55IGRhdGEgd2l0aCBhIGBzc3QyX2NgID4gNTAwLgoKYGBge3IsIGZpZy5jYXA9IkRpc3RyaWJ1dGlvbiBvZiBmaWx0ZXJlZCBgc3N0MmAgZm9yIHRoZSBmb3VyIGluZGl2aWR1YWxzIGluIDIwMTYifQpkYXRhXzIwMTZfZmlsdGVyID0gZGF0YV8yMDE2W3NzdDJfYyA8IDUwMCwgXQpnZ3Bsb3QoZGF0YV8yMDE2X2ZpbHRlciwgYWVzKHggPSBzc3QyX2MsIGZpbGwgPSAuaWQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGZhY2V0X3dyYXAoLmlkIH4gLikgKwogIHRoZW1lX2pqbygpCmBgYAoKV2VsbCwgdGhhdCBzZWVtcyB0byBiZSBtdWNoIGJldHRlciEgSW4gdGhlIHByb2Nlc3Mgb2YgZmlsdGVyaW5nIG91dCBvZGQgdmFsdWVzLCB3ZSByZW1vdmVkIGByIGRhdGFfMjAxNlssLk5dIC0gZGF0YV8yMDE2X2ZpbHRlclssLk5dYCByb3dzIHRoaXMgd2F5OgoKYGBge3J9CiMgbmJyb3cgcmVtb3ZlZApkYXRhXzIwMTZbc3N0Ml9jPjUwMCwuKG5iX3Jvd19yZW1vdmVkID0gLk4pLGJ5PS5pZF0gJT4lCiAgc2FibGUoY2FwdGlvbiA9ICIjIG9mIHJvd3MgcmVtb3ZlZCBieSAyMDE2LWluZGl2aWR1YWxzIikKYGBgCmBgYHtyLCBmaWcuY2FwPSJXaGVyZSBhbmQgd2hlbiB0aGUgYHNzdDJgIG91dGxpZXJzIG9jY3VyZWQiLCBmaWcud2lkdGg9OX0KIyBtYXggZGVwdGgKZ2dwbG90KGRhdGFfMjAxNiwKICAgICAgIGFlcyh5ID0gLW1heHByZXNzX2RiYXJzLCB4PWFzLkRhdGUoZGF0ZSksIGNvbD0uaWQpKSArCiAgZ2VvbV9wYXRoKHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkYXRhXzIwMTZbc3N0Ml9jPjUwMCxdLCBjb2w9ImJsYWNrIikgKwogIHNjYWxlX3hfZGF0ZShkYXRlX2xhYmVscyA9ICIlbS8lWSIpICsKICBsYWJzKHk9IlByZXNzdXJlIChkYmFyKSIsIHg9IkRhdGUiKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuKSArCiAgdGhlbWVfampvKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKQpgYGAKV2VsbCB0aGlzIGxhdHRlciBwbG90IGhpZ2hsaWdodHMgc2V2ZXJhbCBwb2ludHM6CgoqIG1vc3Qgb2YgdGhlIG91dGxpZXJzIG9jY3VyIHdoaWxlIGFuaW1hbHMgc3BlbmQgdGhlIHdob2xlIGRheSBhdCB0aGUgc3VyZmFjZSAob3Igb24gdGhlIGdyb3VuZCksIHByb2JhYmx5IHJlc3RpbmcsIHNvIGVzc2VudGlhbGx5IGF0IHRoZSBiZWdpbm5pbmcgYW5kIHRoZSBlbmQgb2YgZWFjaCB0cmFjawoqIHdlIGNhbiBhbHJlYWR5IHNlZSB0aGF0IGBpbmRfMzQ0OWAgc2VlbXMgdG8gaGF2ZSByZXR1cm4gYXNob3JlIHR3aWNlIGR1cmluZyBoaXMgdHJhY2sKCkxldCdzIHNlZSBpZiB3ZSBjYW4gZG91YmxlIGNoZWNrIHRoYXQsIHVzaW5nIGEgbWFwLgoKYGBge3IsIGZpZy5jYXA9Ikl0IGlzIHN1cHBvc2VkIHRvIGJlIHRoZSB0cmFjayBvZiBgaW5kXzM0NDlgLi4uIChyZWQgZG90cyBhcmUgdGhlIGxvY2F0aW9uIG9mIHJlbW92ZWQgcm93cykiLCBmaWcud2lkdGg9OH0KIyBpbnRlcmFjdGl2ZSBtYXAKbGVhZmxldCgpICU+JQogIHNldFZpZXcobG5nID0gLTEyMiwgbGF0ID0gMzgsIHpvb20gPSAyKSAlPiUKICBhZGRUaWxlcygpICU+JQogIGFkZFBvbHlsaW5lcyhsYXQgPSBkYXRhXzIwMTZbLmlkID09ICJpbmRfMzQ0OSIsIGxhdGl0dWRlX2RlZ3NdLAogICAgICAgICAgICAgICBsbmcgPSBkYXRhXzIwMTZbLmlkID09ICJpbmRfMzQ0OSIsIGxvbmdpdHVkZV9kZWdzXSwKICAgICAgICAgICAgICAgd2VpZ2h0ID0gMikgJT4lCiAgYWRkQ2lyY2xlTWFya2VycyhsYXQgPSBkYXRhXzIwMTZbLmlkID09ICJpbmRfMzQ0OSIgJiBzc3QyX2M+NTAwLCBsYXRpdHVkZV9kZWdzXSwKICAgICAgICAgICAgICAgICAgIGxuZyA9IGRhdGFfMjAxNlsuaWQgPT0gImluZF8zNDQ5IiAmIHNzdDJfYz41MDAsIGxvbmdpdHVkZV9kZWdzXSwKICAgICAgICAgICAgICAgICAgIHJhZGl1cyA9IDMsCiAgICAgICAgICAgICAgICAgICBzdHJva2U9RkFMU0UsCiAgICAgICAgICAgICAgICAgICBjb2xvcj0icmVkIiwKICAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5PTEpCmBgYAoKLi4uIHRoZXNlIGNvb3JkaW5hdGVzIHNlZW0gd2VpcmQgIQoKYGBge3J9CiMgc3VtbWFyeSBvZiB0aGUgY29vcmRpbmF0ZXMgYnkgaW5kaXZpZHVhbHMKZGF0YV8yMDE2WywgLiguaWQsIGxvbmdpdHVkZV9kZWdzLCBsYXRpdHVkZV9kZWdzKV0gJT4lCiAgdGJsX3N1bW1hcnkoYnkgPSAuaWQpICU+JQogIG1vZGlmeV9jYXB0aW9uKCJTdW1tYXJ5IG9mIGBsb25naXR1ZGVfZGVncmVlYCBhbmQgYGxhdGl0dWRlX2RlZ3JlZWAiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9OSwgZmlnLmNhcD0iRGlzdHJpYnV0aW9uIG9mIGNvb3JkaW5hdGVzIHBlciBzZWFsIn0KIyBkaXN0cmlidXRpb24gY29vcmRpbmF0ZXMKZ2dwbG90KAogIGRhdGEgPSBtZWx0KGRhdGFfMjAxNlssIC4oTG9uZ2l0dWRlID0gbG9uZ2l0dWRlX2RlZ3MsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgTGF0aXR1ZGUgPSBsYXRpdHVkZV9kZWdzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5pZCldLCBpZC52YXJzID0KICAgICAgICAgICAgICAgICIuaWQiLCB2YWx1ZS5uYW1lID0gIkNvb3JkaW5hdGUiKSwKICBhZXMoeCA9IENvb3JkaW5hdGUsIGZpbGwgPSAuaWQpCikgKwogIGdlb21faGlzdG9ncmFtKHNob3cubGVnZW5kID0gRikgKwogIGZhY2V0X2dyaWQodmFyaWFibGUgfiAuaWQpICsKICB0aGVtZV9qam8oKQpgYGAKClRoZXJlIGlzIGRlZmluaXRlbHkgc29tZXRoaW5nIHdyb25nIHdpdGggdGhlc2UgY29vcmRpbmF0ZXMgKGZpdmUgc2VhbHMgd291bGQgaGF2ZSBjcm9zc2VkIHRoZSBlcXVhdG9yLi4uKSwgYnV0IHRoZSByZXByZXNlbnRhdGlvbiBvZiB0aGUgdHJhY2sgY2FuIGFsc28gYmUgaW1wcm92ZWQhIEhlcmUgYXJlIHRoZSBzb21lIHBvaW50cyB0byBleHBsb3JlOgoKKiBGb3IgYGxvbmdpdHVkZWAgYSBwYXJ0IG9mIHRoZSBkYXRhIHNlZW1zIHRvIGhhdmUgYSB3cm9uZyBzaWduLCByZXN1bHRpbmcgaW4gdGhlc2UgZGlzdHJpYnV0aW9uLCB0aGF0IGFwcGVhciB0byBiZSBjdXQgb2ZmCiogRm9yIGBsYXRpdHVkZWAsIHdlbGwgdGhpcyBpcyBlbnN1cmUgYnV0IG1heWJlIHRoZSBzYW1lIHByb2JsZW0gb2NjdXJzCgpMZXQncyB0cnkgdG8gcGxheSBvbiBjb29yZGluYXRlcycgc2lnbiB0byBzZWUgaWYgd2UgY2FuIGRpc3BsYXkgc29tZXRoaW5nIHRoYXQgbWFrZXMgbW9yZSBzZW5zZS4KCmBgYHtyLCBmaWcuY2FwPSJBbiBhdHRlbXB0IHRvIGRpc3BsYXkgdGhlIGBpbmRfMzQ0OWAncyB0cmFjayIsIGZpZy53aWR0aD04fQojIGludGVyYWN0aXZlIG1hcApsZWFmbGV0KCkgJT4lCiAgc2V0VmlldyhsbmcgPSAtMTIyLCBsYXQgPSA1MCwgem9vbSA9IDMpICU+JQogIGFkZFRpbGVzKCkgJT4lCiAgYWRkUG9seWxpbmVzKGxhdCA9IGRhdGFfMjAxNlsuaWQgPT0gImluZF8zNDQ5IiwgYWJzKGxhdGl0dWRlX2RlZ3MpXSwKICAgICAgICAgICAgICAgbG5nID0gZGF0YV8yMDE2Wy5pZCA9PSAiaW5kXzM0NDkiLCAtYWJzKGxvbmdpdHVkZV9kZWdzKV0sCiAgICAgICAgICAgICAgIHdlaWdodCA9IDIpCmBgYAoKPiBJJ2xsIGJldHRlciBhc2sgUm94YW5uZSEKCiMjIE1pc3NpbmcgdmFsdWVzCgpgYGB7ciBmaWcuY2FwPSJDaGVjayBmb3IgbWlzc2luZyB2YWx1ZSBpbiAyMDE2LWluZGl2aWR1YWxzIiwgb3V0LndpZHRoPSIxMDAlIn0KIyBidWlsZCBkYXRhc2V0IHRvIGNoZWNrIGZvciBtaXNzaW5nIHZhbHVlcwpkYXRhUGxvdCA9IG1lbHQoZGF0YV8yMDE2X2ZpbHRlclssIC4oLmlkLCBpcy5uYSguU0QpKSwgLlNEY29sID0gLWMoIi5pZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJyZWMjIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRhdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidGltZSIpXSkKIyBhZGQgdGhlIGlkIG9mIHJvd3MKZGF0YVBsb3RbLCBpZF9yb3cgOj0gYygxOi5OKSwgYnkgPSBjKCJ2YXJpYWJsZSIsIi5pZCIpXQoKIyBwbG90CmdncGxvdChkYXRhUGxvdCwgYWVzKHggPSB2YXJpYWJsZSwgeSA9IGlkX3JvdywgZmlsbCA9IHZhbHVlKSkgKwogIGdlb21fdGlsZSgpICsKICBsYWJzKHggPSAiQXR0cmlidXRlcyIsIHkgPSAiUm93cyIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJ3aGl0ZSIsICJibGFjayIpLAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlJlYWwiLCAiTWlzc2luZyIpKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIHRoZW1lX2pqbygpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIikKICApCmBgYAoKIyAyMDE4LWluZGl2aWR1YWxzCgpMZXTigJlzIGhhdmUgYSBsb29rIGF0IHdoYXTigJlzIGluc2lkZSBgZGF0YV9uZXMkZGF0YV8yMDE4YDoKCmBgYHtyfQojIGxpc3Qgc3RydWN0dXJlCnN0cihkYXRhX25lcyR5ZWFyXzIwMTgsIG1heC5sZXZlbCA9IDEsIGdpdmUuYXR0ciA9IEYsIG5vLmxpc3QgPSBUKQpgYGAKCj4gQSBsaXN0IG9mIGByIGxlbmd0aChkYXRhX25lcyR5ZWFyXzIwMTgpYCBgZGF0YS5mcmFtZXNgLCBvbmUgZm9yIGVhY2ggc2VhbAoKRm9yIGNvbnZlbmllbmNlLCB3ZSBhZ2dyZWdhdGUgYWxsIGByIGxlbmd0aChkYXRhX25lcyR5ZWFyXzIwMTgpYCBpbmRpdmlkdWFscyBpbnRvIG9uZSBkYXRhc2V0LgoKYGBge3IsIGV2YWw9RkFMU0V9CiMgY29tYmluZSBhbGwgaW5kaXZpZHVhbHMKZGF0YV8yMDE4ID0gcmJpbmRsaXN0KGRhdGFfbmVzJHllYXJfMjAxOCwgdXNlLm5hbWUgPSBUUlVFLCBpZGNvbCA9IFRSVUUpCgojIGRpc3BsYXkKRFQ6OmRhdGF0YWJsZShkYXRhXzIwMThbc2FtcGxlLmludCguTiwxMDApLF0sb3B0aW9ucz1saXN0KHNjcm9sbFg9VCkpCmBgYApgYGB7ciwgZWNobz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9CiMgY29tYmluZSBhbGwgaW5kaXZpZHVhbHMKZGF0YV8yMDE4ID0gcmJpbmRsaXN0KGRhdGFfbmVzJHllYXJfMjAxOCwgdXNlLm5hbWUgPSBUUlVFLCBpZGNvbCA9IFRSVUUpCgojIHRpdGxlCmNhdCgiPHRhYmxlIHN0eWxlPSd3aWR0aDogNTAlJz4iLHBhc3RlMCgiPGNhcHRpb24+IiwgIigjdGFiOm15RFRodG1sdG9vbHMpIiwgIlNhbXBsZSBvZiAxMDAgcmFuZG9tIHJvd3MgZnJvbSBgZGF0YV8yMDE4YCIsICI8L2NhcHRpb24+IiksIjwvdGFibGU+Iiwgc2VwID0iXG4iKQoKIyBkaXNwbGF5CgpEVDo6ZGF0YXRhYmxlKGRhdGFfMjAxOFtzYW1wbGUuaW50KC5OLDEwMCksXSxvcHRpb25zPWxpc3Qoc2Nyb2xsWD1UKSkKYGBgCgojIyBTdW1tYXJ5CgpgYGB7cn0KIyByYXdfZGF0YQpkYXRhXzIwMThbLCAuKAogIG5iX2RheXNfcmVjb3JkZWQgPSB1bmlxdWVOKGFzLkRhdGUoZGF0ZSkpLAogIG5iX2RpdmVzID0gLk4sCiAgbWF4ZGVwdGhfbWVhbiA9IG1lYW4obWF4ZGVwdGgpLAogIGRkdXJhdGlvbl9tZWFuID0gbWVhbihkZHVyYXRpb24pLAogIGJvdHR0aW1lX21lYW4gPSBtZWFuKGJvdHR0aW1lKSwKICBwZGlfbWVhbiA9IG1lYW4ocGRpLCBuYS5ybT1UKQopLCBieSA9LmlkXSAlPiUKICBzYWJsZShjYXB0aW9uPSJTdW1tYXJ5IGRpdmluZyBpbmZvcm1hdGlvbiByZWxhdGl2ZSB0byBlYWNoIDIwMTggaW5kaXZpZHVhbCIsIAogICAgICAgIGRpZ2l0cz0yKQpgYGAKPiBWZXJ5IG5pY2UgZGF0YXNldCA6KQoKIyMgU29tZSBleHBsYW5hdG9yeSBwbG90cwoKIyMjIE1pc3NpbmcgdmFsdWVzCgpgYGB7ciBmaWcuY2FwPSJDaGVjayBmb3IgbWlzc2luZyB2YWx1ZSBpbiAyMDE4LWluZGl2aWR1YWxzIiwgZmlnLndpZHRoPTl9CiMgYnVpbGQgZGF0YXNldCB0byBjaGVjayBmb3IgbWlzc2luZyB2YWx1ZXMKZGF0YVBsb3QgPSBtZWx0KGRhdGFfMjAxOFssIC4oLmlkLCBpcy5uYSguU0QpKSwgLlNEY29sID0gLWMoIi5pZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJkaXZlbnVtYmVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInllYXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibW9udGgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZGF5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImhvdXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNlYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJqdWxkYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRpdmV0eXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRhdGUiKV0pCiMgYWRkIHRoZSBpZCBvZiByb3dzCmRhdGFQbG90WywgaWRfcm93IDo9IGMoMTouTiksIGJ5ID0gYygidmFyaWFibGUiLCIuaWQiKV0KCiMgcGxvdApnZ3Bsb3QoZGF0YVBsb3QsIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBpZF9yb3csIGZpbGwgPSB2YWx1ZSkpICsKICBnZW9tX3RpbGUoKSArCiAgbGFicyh4ID0gIkF0dHJpYnV0ZXMiLCB5ID0gIlJvd3MiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygid2hpdGUiLCAiYmxhY2siKSwKICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJSZWFsIiwgIk1pc3NpbmciKSkgKwogIGZhY2V0X3dyYXAoLmlkIH4gLiwgc2NhbGVzID0gImZyZWVfeSIpICsKICB0aGVtZV9qam8oKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksCiAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIpCiAgKQpgYGAKClNvIGZhciBzbyBnb29kLCBvbmx5IGZldyB2YXJpYWJsZXMgc2VlbXMgdG8gaGF2ZSBtaXNzaW5nIHZhbHVlczoKCmBgYHtyfQojIHRhYmxlIHdpdGggcGVyY2VudAp0YWJsZV9pbnRlciA9IGRhdGFfMjAxOFssIGxhcHBseSguU0QsIGZ1bmN0aW9uKHgpIHsKICByb3VuZChsZW5ndGgoeFtpcy5uYSh4KV0pICogMTAwIC8gbGVuZ3RoKHgpLCAxKQp9KSwgLlNEY29sID0gLWMoCiAgIi5pZCIsCiAgImRpdmVudW1iZXIiLAogICJ5ZWFyIiwKICAibW9udGgiLAogICJkYXkiLAogICJob3VyIiwKICAibWluIiwKICAic2VjIiwKICAianVsZGF0ZSIsCiAgImRpdmV0eXBlIiwKICAiZGF0ZSIKKV0KCiMgZmluZCB3aGljaCBhcmUgZGlmZmVyZW50IGZyb20gMApjb25kX2ludGVyID0gc2FwcGx5KHRhYmxlX2ludGVyLGZ1bmN0aW9uKHgpe3g9PTB9KQoKIyBkaXNwbGF5IHRoZSBwZXJjZW50YWdlcyB0aGF0IGFyZSBvdmVyIDAKdGFibGVfaW50ZXJbLHdoaWNoKGNvbmRfaW50ZXIpIDo9IE5VTExdICU+JQogIHNhYmxlKGNhcHRpb249IlBlcmNlbnRhZ2Ugb2YgbWlzc2luZyB2YWx1ZXMgcGVyIGNvbHVtbnMgaGF2aW5nIG1pc3NpbmcgdmFsdWVzISIpJT4lIAogIHNjcm9sbF9ib3god2lkdGggPSAiMTAwJSIpCmBgYAoKIyMjIE91dGxpZXJzIHsudGFic2V0fQoKT2ssIGxldCdzIGhhdmUgYSBsb29rIGF0IGFsbCB0aGUgZGF0YS4gQnV0IGZpcnN0LCB3ZSBoYXZlIHRvIHJlbW92ZSBvdXRsaWVycy4gU29tZSBvZiB0aGVtIGFyZSBxdWlldCBlYXN5IHRvIHNwb3QgbG9va2luZyBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGRpdmUgZHVyYXRpb246CgojIyMjIEJlZm9yZSB7LX0KCmBgYHtyLCBmaWcuY2FwPSdEaXN0cmlidXRpb24gb2YgYGRkdXJhdGlvbmAgZm9yIGVhY2ggc2VhbC4gVGhlIGRhc2hlZCBsaW5lIGhpZ2hsaWdodCB0aGUgInN1YmplY3RpdmUiIHRocmVzaG9sZCB1c2VkIHRvIHJlbW92ZSBvdXRsaWVycyAoMzAwMCBzZWMpJywgZmlnLmhlaWdodD0zfQpnZ3Bsb3QoZGF0YV8yMDE4WywuU0RdWyxzdGF0ZTo9IkJlZm9yZSJdLCAKICAgICAgIGFlcyh4PWRkdXJhdGlvbiwgZmlsbCA9IC5pZCkpKwogIGdlb21faGlzdG9ncmFtKHNob3cubGVnZW5kID0gRkFMU0UpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDMwMDAsIGxpbmV0eXBlID0gImxvbmdkYXNoIikgKwogIGZhY2V0X2dyaWQoc3RhdGV+LmlkLAogICAgICAgICAgICAgc2NhbGVzPSJmcmVlIikrCiAgbGFicyh5PSIjIG9mIGRpdmVzIiwgeD0iRGl2ZSBkdXJhdGlvbiAocykiKSsKICB0aGVtZV9qam8oKQoKYGBgCgojIyMjIEFmdGVyIHstfQoKYGBge3IsIGZpZy5jYXA9J1NhbWUgZGlzdHJpYnV0aW9uIG9mIGBkZHVyYXRpb25gIGZvciBlYWNoIHNlYWwgYnV0IGFmdGVyIHJlbW92aW5nIGFueSBgZGR1cmF0aW9uYCA+IDMwMDAgc2VjLiBUaGUgZGFzaGVkIGxpbmUgaGlnaGxpZ2h0IHRoZSAic3ViamVjdGl2ZSIgdGhyZXNob2xkIHVzZWQgdG8gcmVtb3ZlIG91dGxpZXJzJywgZmlnLmhlaWdodD0zfQpnZ3Bsb3QoZGF0YV8yMDE4W2RkdXJhdGlvbjwzMDAwLF1bXVssc3RhdGU6PSJBZnRlciJdLCAKICAgICAgIGFlcyh4PWRkdXJhdGlvbiwgZmlsbCA9IC5pZCkpKwogIGdlb21faGlzdG9ncmFtKHNob3cubGVnZW5kID0gRkFMU0UpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDMwMDAsIGxpbmV0eXBlID0gImxvbmdkYXNoIikgKwogIGZhY2V0X2dyaWQoc3RhdGV+LmlkLAogICAgICAgICAgICAgc2NhbGVzPSJmcmVlIikrCiAgbGFicyh4PSIjIG9mIGRpdmVzIiwgeT0iRGl2ZSBkdXJhdGlvbiAocykiKSsKICB0aGVtZV9qam8oKQpgYGAKSXQgc2VlbXMgbXVjaGUgYmV0dGVyLCBzbyBsZXQncyByZW1vdmUgYW55IHJvd3Mgd2l0aCBgZGR1cmF0aW9uYCA+IDMwMDAgc2VjLgoKYGBge3J9CiMgZmlsdGVyIGRhdGEKZGF0YV8yMDE4X2ZpbHRlciA9IGRhdGFfMjAxOFtkZHVyYXRpb24gPCAzMDAwLCBdCgojIG5icm93IHJlbW92ZWQKZGF0YV8yMDE4W2RkdXJhdGlvbj49IDMwMDAsLihuYl9yb3dfcmVtb3ZlZCA9IC5OKSxieT0uaWRdICU+JQogIHNhYmxlKGNhcHRpb24gPSAiIyBvZiByb3dzIHJlbW92ZWQgYnkgMjAxOC1pbmRpdmlkdWFscyIpCmBgYAoKIyMjIEFsbCBWYXJpYWJsZXMgey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9CgpgYGB7ciwgcmVzdWx0cz0nYXNpcycsIGNhY2hlPVRSVUV9Cm5hbWVzX2Rpc3BsYXkgPSBuYW1lcyhkYXRhXzIwMThfZmlsdGVyWywgLWMoCiAgIi5pZCIsCiAgImRhdGUiLAogICJkaXZlbnVtYmVyIiwKICAieWVhciIsCiAgIm1vbnRoIiwKICAiZGF5IiwKICAiaG91ciIsCiAgIm1pbiIsCiAgInNlYyIsCiAgImp1bGRhdGUiLAogICJkaXZldHlwZSIsCiAgImV1cGhvdGljZGVwdGgiLAogICJ0aGVybW9jbGluZWRlcHRoIiwKICAiZGF5X2RlcGFydHVyZSIKKV0pCmZvciAoaSBpbiBuYW1lc19kaXNwbGF5KSB7CiAgY2F0KCcjIyMjJywgaSwgJ3stfSBcbicpCiAgaWYgKGkgPT0gIm1heGRlcHRoIikgewogICAgcHJpbnQoCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXJbLCAuKC5pZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVybW9jbGluZWRlcHRoKV0sCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBhcy5EYXRlKGRhdGUpLAogICAgICAgICAgICB5ID0gLXRoZXJtb2NsaW5lZGVwdGgsCiAgICAgICAgICAgIGNvbG91ciA9ICJUaGVybW9jbGluZSAobSkiCiAgICAgICAgICApLAogICAgICAgICAgCiAgICAgICAgICBhbHBoYSA9IC4yLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgZ2VvbV9wb2ludCgKICAgICAgICAgIGRhdGEgPSBkYXRhXzIwMThfZmlsdGVyWywgLiguaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXVwaG90aWNkZXB0aCldLAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gYXMuRGF0ZShkYXRlKSwKICAgICAgICAgICAgeSA9IC1ldXBob3RpY2RlcHRoLAogICAgICAgICAgICBjb2xvdXIgPSAiRXVwaG90aWMgKG0pIgogICAgICAgICAgKSwKICAgICAgICAgIGFscGhhID0gLjIsCiAgICAgICAgICBzaXplID0gLjUKICAgICAgICApICsKICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKAogICAgICAgICAgdmFsdWVzID0gYygiVGhlcm1vY2xpbmUgKG0pIiA9ICdyZWQnLAogICAgICAgICAgICAgICAgICAgICAiRXVwaG90aWMgKG0pIiA9ICJibGFjayIpLAogICAgICAgICAgbmFtZSA9ICJab25lIgogICAgICAgICkgKwogICAgICAgIG5ld19zY2FsZV9jb2xvcigpICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgZGF0YSA9IG1lbHQoZGF0YV8yMDE4X2ZpbHRlclssIC4oLmlkLCBkYXRlLCBnZXQoaSkpXSwgaWQudmFycyA9IGMoIi5pZCIsICJkYXRlIikpLAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gYXMuRGF0ZShkYXRlKSwKICAgICAgICAgICAgeSA9IC12YWx1ZSwKICAgICAgICAgICAgY29sID0gLmlkCiAgICAgICAgICApLAogICAgICAgICAgYWxwaGEgPSAxIC8gMTAsCiAgICAgICAgICBzaXplID0gLjUsCiAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgICAgICAgKSArCiAgICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgICBzY2FsZV94X2RhdGUoZGF0ZV9sYWJlbHMgPSAiJW0vJVkiKSArCiAgICAgICAgbGFicyh4ID0gIkRhdGUiLCB5ID0gIk1heGltdW0gRGVwdGggKG0pIikgKwogICAgICAgIHRoZW1lX2pqbygpICsKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikKICAgICkKICAgIGNhdCgiPGJsb2NrcXVvdGU+IENvbnNpZGVyaW5nIGBpbmRfMjAxODA3NGAgaGFzIHNsaWdodGx5IGRpZmZlcmVudCB2YWx1ZXMgdGhhbiBvdGhlciBpbmRpdmlkdWFscyBmb3IgdGhlIHRoZXJtb2NsaW5lIGRlcHRoLCBpdCB3b3VsZCBiZSBpbnRlcmVzdGluZyB0byBzZWUgd2hlcmUgdGhlIGFuaW1hbCB3ZW50LiA8L2Jsb2NrcXVvdGU+IikKICB9IGVsc2UgewogICAgcHJpbnQoCiAgICAgIGdncGxvdCgKICAgICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyWywgLiguaWQsIGRhdGUsIGdldChpKSldLCBpZC52YXJzID0gYygiLmlkIiwgImRhdGUiKSksCiAgICAgICAgYWVzKAogICAgICAgICAgeCA9IGFzLkRhdGUoZGF0ZSksCiAgICAgICAgICB5ID0gdmFsdWUsCiAgICAgICAgICBjb2wgPSAuaWQKICAgICAgICApCiAgICAgICkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgYWxwaGEgPSAxIC8gMTAsCiAgICAgICAgICBzaXplID0gLjUKICAgICAgICApICsKICAgICAgICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgICAgIHNjYWxlX3hfZGF0ZShkYXRlX2xhYmVscyA9ICIlbS8lWSIpICsKICAgICAgICBsYWJzKHggPSAiRGF0ZSIsIHkgPSBpKSArCiAgICAgICAgdGhlbWVfampvKCkgKwogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCiAgICApCiAgfQogIAogIGNhdCgnIFxuIFxuJykKfQpgYGAKCiMjIyB7LnVubGlzdGVkIC51bm51bWJlcmVkfQoKPiBGZXcgcXVlc3Rpb25zLCB0aGF0IEkgc2hvdWxkIGxvb2sgaW50byBpdDoKPgo+ICogaXMgdGhlIGJpbW9kYWwgZGlzdHJpYnV0aW9uIG9mIGBkZHVyYXRpb25gLCBgZGVzY3RpbWVgIGR1ZSB0byBueWN0aGVtZXJhbCBtaWdyYXRpb24/Cj4gKiBpcyB0aGUgYmltb2RhbCBkaXN0cmlidXRpb24gb2YgYGRlc2NyYXRlYCAoZXNwZWNpYWxseSBmb3IgYGluZDIwMTgwNzBgIGFuZCBgaW5kXzIwMTgwNzJgKSBkdWUgdG8gZHJpZnQgZGl2ZT8KPiAqIGlzIGBsaWdodGF0Ym90dGAgY291bGQgYmUgdXNlZCB0byBpZGVudGlmeSBiaW9sdW1pbmVzY2VuY2UsIGNhdXNlIGl0IHNlZW1zIHRoZXJlIGlzIGEgbG90IGdvaW5nIG9uIGF0IHRoZSBib3R0b20/Cj4gKiBhcmUgdGhlIHZhcmlhdGlvbnMgb2JzZXJ2ZWQgZm9yIGBsaWdodGF0c3VyZmAgaXMgZHVlIHRvIG1vb24gY3ljbGU/Cj4gKiBub3Qgc3VyZSB3aHkgaXMgdGhlcmUgYSBiaW1vZGFsIGRpc3RyaWJ1dGlvbiBvZiBgdGVtcGF0Ym90dGAhCj4gKiBgZHJpZnJhdGVgIHRoYXQgb25lIGlzIGF3ZXNvbWUsIHNpbmNlIHdlIGNhbiBjbGVhcmx5IHNlZSBhIHBhdHRlcm4gb2YgaG93IGRyaWZ0cmF0ZSAoYW5kIHNvIGJ1b3lhbmN5KSBjaGFuZ2UgYWNjb3JkaW5nIHRpbWUsIGJ1dCBpdCBpcyBub2lzeSBkdWUgdG8gbmVnYXRpdmUgYW5kIHBvc2l0aXZlIHZhbHVlcyBvY2N1cnJpbmcgZXZlbiBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSB0cmlwLiBJIGd1ZXNzIHlvdSBtZWFzdXJlIGRyaWZ0cmF0ZSBhbHNvIGluIGFzY2VudCBwaGFzZXM/IFRoYXQgZmlndXJlIGlsbHVzdHJhdGUgc29tZXRoaW5nIHdlIGFsc28gZm91bmQgb24gU291dGhlcm4gZWxlcGhhbnQgc2VhbHMsIHRoYXQgZHJpZnQgcmF0ZSB2YXJpZXMgYXQgdGhlIGRlc2NlbnQsIGJ1dCByYXJlbHkgYXQgdGhlIGFzY2VudC4gSWYgSSB3ZWxsIHJlbWVtYmVyLCB0byBtYWludGFpbiBhIGNvbnN0YW50IGRyaWZ0IHJhdGUgaW4gYXNjZW50IHBoYXNlIGR1cmluZyB0aGUgd2hvbGUgdHJpcCwgU291dGhlcm4gZWxlcGhhbnQgYWRqdXN0IHRoZWlyIHBpdGNoIChkaXZpbmcgYW5nbGUpCj4gKiB0aGUgYmltb2RhbCBkaXN0cmlidXRpb24gb2YgYHZlcnRpY2Fsc3BlZWQ5MGAgYW5kIGB2ZXJ0aWNhbHNwZWVkOTVgIHNob3VsZCBiZSBkdWUgdG8gZHJpZnQgZGl2ZS4KCiMjIyBBbGwgVmFyaWFibGVzIGR1cmluZyB0aGUgZmlyc3QgbW9udGggey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9CgpgYGB7ciwgcmVzdWx0cz0nYXNpcycsIGNhY2hlPVRSVUV9CmZvciAoaSBpbiBuYW1lc19kaXNwbGF5KSB7CiAgY2F0KCcjIyMjJywgaSwgJ3stfSBcbicpCiAgaWYgKGkgPT0gIm1heGRlcHRoIikgewogICAgcHJpbnQoCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXJbZGF5X2RlcGFydHVyZSA8IDMyLCAuKC5pZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheV9kZXBhcnR1cmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVybW9jbGluZWRlcHRoKV0sCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgICAgICAgICB5ID0gLXRoZXJtb2NsaW5lZGVwdGgsCiAgICAgICAgICAgIGNvbG91ciA9ICJUaGVybW9jbGluZSAobSkiLAogICAgICAgICAgICBncm91cCA9IGRheV9kZXBhcnR1cmUKICAgICAgICAgICksCiAgICAgICAgICAKICAgICAgICAgIGFscGhhID0gLjIsCiAgICAgICAgICBzaXplID0gLjUKICAgICAgICApICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXJbZGF5X2RlcGFydHVyZSA8IDMyLCAuKC5pZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheV9kZXBhcnR1cmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBldXBob3RpY2RlcHRoKV0sCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgICAgICAgICB5ID0gLWV1cGhvdGljZGVwdGgsCiAgICAgICAgICAgIGNvbG91ciA9ICJFdXBob3RpYyAobSkiLAogICAgICAgICAgICBncm91cCA9IGRheV9kZXBhcnR1cmUKICAgICAgICAgICksCiAgICAgICAgICBhbHBoYSA9IC4yLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCgKICAgICAgICAgIHZhbHVlcyA9IGMoIlRoZXJtb2NsaW5lIChtKSIgPSAncmVkJywKICAgICAgICAgICAgICAgICAgICAgIkV1cGhvdGljIChtKSIgPSAiYmxhY2siKSwKICAgICAgICAgIG5hbWUgPSAiWm9uZSIKICAgICAgICApICsKICAgICAgICBuZXdfc2NhbGVfY29sb3IoKSArCiAgICAgICAgZ2VvbV9ib3hwbG90KAogICAgICAgICAgZGF0YSA9IG1lbHQoZGF0YV8yMDE4X2ZpbHRlcltkYXlfZGVwYXJ0dXJlIDwgMzIsIC4oLmlkLCBkYXlfZGVwYXJ0dXJlLCBnZXQoaSkpXSwgaWQudmFycyA9IGMoIi5pZCIsICJkYXlfZGVwYXJ0dXJlIikpLAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gZGF5X2RlcGFydHVyZSwKICAgICAgICAgICAgeSA9IC12YWx1ZSwKICAgICAgICAgICAgY29sID0gLmlkLAogICAgICAgICAgICBncm91cCA9IGRheV9kZXBhcnR1cmUKICAgICAgICAgICksCiAgICAgICAgICBhbHBoYSA9IDEgLyAxMCwKICAgICAgICAgIHNpemUgPSAuNSwKICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UKICAgICAgICApICsKICAgICAgICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgICAgIGxhYnMoeCA9ICIjIGRheXMgc2luY2UgZGVwYXJ0dXJlIiwgeSA9ICJNYXhpbXVtIERlcHRoIChtKSIpICsKICAgICAgICB0aGVtZV9qam8oKSArCiAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKQogICAgKQogIH0gZWxzZSB7CiAgICBwcmludCgKICAgICAgZ2dwbG90KAogICAgICAgIGRhdGEgPSBtZWx0KGRhdGFfMjAxOF9maWx0ZXJbZGF5X2RlcGFydHVyZSA8IDMyLCAuKC5pZCwgZGF5X2RlcGFydHVyZSwgZ2V0KGkpKV0sIGlkLnZhcnMgPSBjKCIuaWQiLCAiZGF5X2RlcGFydHVyZSIpKSwKICAgICAgICBhZXMoCiAgICAgICAgICB4ID0gZGF5X2RlcGFydHVyZSwKICAgICAgICAgIHkgPSB2YWx1ZSwKICAgICAgICAgIGNvbG9yID0gLmlkLAogICAgICAgICAgZ3JvdXAgPSBkYXlfZGVwYXJ0dXJlCiAgICAgICAgKQogICAgICApICsKICAgICAgICBnZW9tX2JveHBsb3QoCiAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgYWxwaGEgPSAxIC8gMTAsCiAgICAgICAgICBzaXplID0gLjUKICAgICAgICApICsKICAgICAgICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgICAgIGxhYnMoeCA9ICIjIGRheXMgc2luY2UgZGVwYXJ0dXJlIiwgeSA9IGkpICsKICAgICAgICB0aGVtZV9qam8oKQogICAgKQogIH0KICAKICBjYXQoJyBcbiBcbicpCn0KYGBgCgojIyMgQ29ycmVsYXRpb24KCkNhbiB3ZSBmaW5kIG5pY2UgY29ycmVsYXRpb24/CgpgYGB7ciwgZmlnLmNhcD0iQ29ycmVsYXRpb24gbWF0cml4IChjcm9zc2VzIGluZGljYXRlIG5vbiBzaWduaWZpY2FudCBjb3JyZWxhdGlvbikiLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CiMgY29tcHV0ZSBjb3JyZWxhdGlvbgpjb3JyXzIwMTggPSByb3VuZChjb3IoZGF0YV8yMDE4X2ZpbHRlclssIG5hbWVzX2Rpc3BsYXksIHdpdGggPSBGXSwgCiAgICAgICAgICAgICAgICAgICAgICB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIiksIDEpCgojIHJlcGxhY2UgTkEgdmFsdWUgYnkgMApjb3JyXzIwMThbaXMubmEoY29ycl8yMDE4KV0gPSAwCgojIGNvbXB1dGUgcF92YWx1ZXMKY29ycl9wXzIwMTggPSBjb3JfcG1hdChkYXRhXzIwMThfZmlsdGVyWywgbmFtZXNfZGlzcGxheSwgd2l0aCA9IEZdKQoKIyByZXBsYWNlIE5BIHZhbHVlIGJ5IDAKY29ycl9wXzIwMThbaXMubmEoY29ycl9wXzIwMTgpXSA9IDEKCiMgZGlzcGxheQpnZ2NvcnJwbG90KAogIGNvcnJfMjAxOCwKICBwLm1hdCA9IGNvcnJfcF8yMDE4LAogIGhjLm9yZGVyID0gVFJVRSwKICBtZXRob2QgPSAiY2lyY2xlIiwKICB0eXBlID0gImxvd2VyIiwKICBnZ3RoZW1lID0gdGhlbWVfampvKCksCiAgc2lnLmxldmVsID0gMC4wNSwKICBjb2xvcnMgPSAgYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKQopCmBgYAoKQW5vdGhlciB3YXkgdG8gc2VlIGl0OgoKYGBge3J9CiMgZmxhdHRlbiBjb3JyZWxhdGlvbiBtYXRyaXgKY29yX3Jlc3VsdF8yMDE4ID0gZmxhdF9jb3JfbWF0KGNvcnJfMjAxOCwgY29ycl9wXzIwMTgpCgojIGtlZXAgb25seSB0aGUgb25lIGFib3ZlIC43CmNvcl9yZXN1bHRfMjAxOFtjb3I+PS43LF1bb3JkZXIoLWFicyhjb3IpKV0gJT4lCiAgc2FibGUoY2FwdGlvbj0iUGFpcndpc2UgY29ycmVsYXRpb24gYWJvdmUgMC43NSBhbmQgYXNzb2NpYXRlZCBwLXZhbHVlcyIpCmBgYAoKPiBJIGd1ZXNzIG5vdGhpbmcgdW5leHBlY3RlZCBoZXJlLCBJJ2xsIGhhdmUgdG8gY2hlY2sgd2l0aCBQYXRyaWNrIGFib3V0IHRoZSBlZmZpY2llbmN5IDspCgojIyBEaXZlIFR5cGUKCmBgYHtyLCBmaWcuY2FwPSJQcm9wb3J0aW9uIGRpdmUgdHlwZXMifQojIGRhdGFzZXQgdG8gcGxvdCBwcm9wb3J0aW9uYWwgYXJlYSBwbG90CmRhdGFfMjAxOF9maWx0ZXJbLCBzdW1faWQgOj0gLk4sIGJ5ID0gLiguaWQsIGRheV9kZXBhcnR1cmUpXVssIHN1bV9pZF9kYXlzIDo9IC5OLCBieSA9IC4oLmlkLCBkYXlfZGVwYXJ0dXJlLCBkaXZldHlwZSldWywgcHJvcCA6PSBzdW1faWRfZGF5cyAvCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtX2lkXQpkYXRhUGxvdCA9IHVuaXF1ZShkYXRhXzIwMThfZmlsdGVyWywgLihwcm9wLCAuaWQsIGRpdmV0eXBlLCBkYXlfZGVwYXJ0dXJlKV0pCgojIGFyZWEgcGxvdApnZ3Bsb3QoZGF0YVBsb3QsIGFlcygKICB4ID0gYXMubnVtZXJpYyhkYXlfZGVwYXJ0dXJlKSwKICB5ID0gcHJvcCwKICBmaWxsID0gYXMuY2hhcmFjdGVyKGRpdmV0eXBlKQopKSArCiAgZ2VvbV9hcmVhKGFscGhhID0gMC42ICwgc2l6ZSA9IDEpICsKICBmYWNldF93cmFwKC5pZCB+IC4sIHNjYWxlcyA9ICJmcmVlIikgKwogIHRoZW1lX2pqbygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsKICBsYWJzKHg9IiMgb2YgZGF5cyBzaW5jZSBkZXBhcnR1cmUiLCB5PSJQcm9wb3J0aW9uIG9mIGRpdmVzIiwgZmlsbCA9ICJEaXZlIHR5cGVzIikKYGBgCgojIyBEaXZlIGR1cmF0aW9uICp2cy4qIE1heGltdW0gZGVwdGggey50YWJzZXR9CgojIyMgQ29sb3JlZCBieSBJRAoKYGBge3IsIGZpZy5jYXA9IkRpdmUgZHVyYXRpb24gdnMuIE1heGltdW0gRGVwdGggY29sb3JlZCAyMDE4LWluZGl2aWR1YWxzIn0KIyBwbG90CmdncGxvdChkYXRhID0gZGF0YV8yMDE4X2ZpbHRlciwgYWVzKHkgPSBkZHVyYXRpb24sIHggPSBtYXhkZXB0aCwgY29sID0gLmlkKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IC41LCBhbHBoYSA9IC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuKSArCiAgbGFicyh4PSJNYXhpbXVtIGRlcHRoIChtKSIsIHk9IkRpdmUgZHVyYXRpb24gKHMpIikrCiAgdGhlbWVfampvKCkKYGBgCgoKIyMjIENvbG9yZWQgYnkgRGl2ZSBUeXBlCgpgYGB7ciwgZmlnLmNhcD0iRGl2ZSBkdXJhdGlvbiB2cy4gTWF4aW11bSBEZXB0aCBjb2xvcmVkIGJ5IERpdmUgVHlwZSJ9CiMgcGxvdApnZ3Bsb3QoZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXIsIGFlcyh5ID0gZGR1cmF0aW9uLCB4ID0gbWF4ZGVwdGgsIGNvbCA9IGRpdmV0eXBlKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IC41LCBhbHBoYSA9IC4xKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuKSArCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA1LCBhbHBoYSA9IDEpKSkgKwogIGxhYnMoeD0iTWF4aW11bSBkZXB0aCAobSkiLCB5PSJEaXZlIGR1cmF0aW9uIChzKSIpKwogIHRoZW1lX2pqbygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpCmBgYAoKIyMjIENvbG9yZWQgYnkgIyBkYXlzIHNpbmNlIGRlcGFydHVyZQoKYGBge3IsIGZpZy5jYXA9IkRpdmUgZHVyYXRpb24gdnMuIE1heGltdW0gRGVwdGggY29sb3JlZCBieSAjIGRheXMgc2luY2UgZGVwYXJ0dXJlIn0KIyBwbG90CmdncGxvdChkYXRhID0gZGF0YV8yMDE4X2ZpbHRlclsscHJvcF90cmFjayA6PSAoZGF5X2RlcGFydHVyZSoxMDApL21heChkYXlfZGVwYXJ0dXJlKSxieT0uaWRdLCBhZXMoeSA9IGRkdXJhdGlvbiwgeCA9IG1heGRlcHRoLCBjb2wgPSBwcm9wX3RyYWNrKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IC41LCBhbHBoYSA9IC4xKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuKSArCiAgbGFicyh4PSJNYXhpbXVtIGRlcHRoIChtKSIsIHk9IkRpdmUgZHVyYXRpb24gKHMpIiwgY29sPSJQcm9wb3J0aW9uIG9mIGNvbXBsZXRlZCB0cmFjayAoJSkiKSsKICBzY2FsZV9jb2xvcl9jb250aW51b3VzKHR5cGUgPSAidmlyaWRpcyIpKwogIHRoZW1lX2pqbygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpCmBgYAoKPiBUaGVyZSBzZWVtcyB0byBiZSBhICpwYXRjaCogZm9yIGhpZ2ggZGVwdGhzIChlc3BlY2lhbGx5IHZpc2libGUgZm9yIGBpbmQyMDE4MDcwYCksIGJ1dCBJIGRvbid0IGtub3cgd2hhdCBpdCBjb3VsZCBiZSBsaW5rZWQgdG8uLi4KCiMjIERyaWZ0IFJhdGUKCk5vdCBzdXJlIGFib3V0IHRoZXNlIGdyYXBocywgZXNwZWNpYWx5IGlmIGBkcmlmdHJhdGVgIGlzIGNhbGN1bGF0ZWQgZHVyaW5nIGJvdGggYXNjZW50IGFuZCBkZXNjZW50IHBoYXNlcy4KCmBgYHtyLCBmaWcuY2FwPSJEcmlmdCByYXRlIHZzLiBCb3R0b20gdGltZSIsIGZpZy5oZWlnaHQ9N30KIyBwbG90CmdncGxvdChkYXRhXzIwMThfZmlsdGVyWywuKGRyaWZ0cmF0ZT1tZWRpYW4oZHJpZnRyYXRlLG5hLnJtPVQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBib3R0dGltZT1tZWRpYW4oYm90dHRpbWUsbmEucm09VCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heGRlcHRoPW1lZGlhbihtYXhkZXB0aCxuYS5ybT1UKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZGR1cmF0aW9uPW1lZGlhbihkZHVyYXRpb24sbmEucm09VCkpLCBieT0uKC5pZCxkYXlfZGVwYXJ0dXJlKV0sCiAgICAgICBhZXMoeD1ib3R0dGltZSwgeT1kcmlmdHJhdGUsIGNvbD0uaWQpKSsKICBnZW9tX3BvaW50KHNpemU9LjUsYWxwaGE9LjUpKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSsKICBndWlkZXMoY29sb3I9RkFMU0UpKwogIGZhY2V0X3dyYXAoLmlkfi4pKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsNzAwKSkrCiAgbGFicyh4ID0gIkRhaWx5IG1lZGlhbiBCb3R0b20gdGltZSAocykiLCB5ID0gIkRhaWx5IG1lZGlhbiBkcmlmdCByYXRlIChtLnMtMSkiKSsKICB0aGVtZV9qam8oKQpgYGAKCmBgYHtyLCBmaWcuY2FwPSJEcmlmdCByYXRlIHZzLiBNYXhpbXVtIGRlcHRoIiwgZmlnLmhlaWdodD03fQojIHBsb3QKZ2dwbG90KGRhdGFfMjAxOF9maWx0ZXJbLC4oZHJpZnRyYXRlPW1lZGlhbihkcmlmdHJhdGUsbmEucm09VCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdHR0aW1lPW1lZGlhbihib3R0dGltZSxuYS5ybT1UKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4ZGVwdGg9bWVkaWFuKG1heGRlcHRoLG5hLnJtPVQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBkZHVyYXRpb249bWVkaWFuKGRkdXJhdGlvbixuYS5ybT1UKSksIGJ5PS4oLmlkLGRheV9kZXBhcnR1cmUpXSwKICAgICAgIGFlcyh4PW1heGRlcHRoLCB5PWRyaWZ0cmF0ZSwgY29sPS5pZCkpKwogIGdlb21fcG9pbnQoc2l6ZT0uNSxhbHBoYT0uNSkrCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpKwogIGd1aWRlcyhjb2xvcj1GQUxTRSkrCiAgZmFjZXRfd3JhcCguaWR+LikrCiAgbGFicyh4ID0gIkRhaWx5IG1lZGlhbiBNYXhpbXVtIGRlcHRoIChtKSIsIHkgPSAiRGFpbHkgbWVkaWFuIGRyaWZ0IHJhdGUgKG0ucy0xKSIpKwogIHRoZW1lX2pqbygpCmBgYAoKYGBge3IsIGZpZy5jYXA9IkRyaWZ0IHJhdGUgdnMuIERpdmUgZHVyYXRpb24iLCBmaWcuaGVpZ2h0PTd9CiMgcGxvdApnZ3Bsb3QoZGF0YV8yMDE4X2ZpbHRlclssLihkcmlmdHJhdGU9bWVkaWFuKGRyaWZ0cmF0ZSxuYS5ybT1UKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYm90dHRpbWU9bWVkaWFuKGJvdHR0aW1lLG5hLnJtPVQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhkZXB0aD1tZWRpYW4obWF4ZGVwdGgsbmEucm09VCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRkdXJhdGlvbj1tZWRpYW4oZGR1cmF0aW9uLG5hLnJtPVQpKSwgYnk9LiguaWQsZGF5X2RlcGFydHVyZSldLAogICAgICAgYWVzKHg9ZGR1cmF0aW9uLCB5PWRyaWZ0cmF0ZSwgY29sPS5pZCkpKwogIGdlb21fcG9pbnQoc2l6ZT0uNSxhbHBoYT0uNSkrCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpKwogIGd1aWRlcyhjb2xvcj1GQUxTRSkrCiAgZmFjZXRfd3JhcCguaWR+LikrCiAgbGFicyh4ID0gIkRhaWx5IG1lZGlhbiBEaXZlIGR1cmF0aW9uIChzKSIsIHkgPSAiRGFpbHkgbWVkaWFuIGRyaWZ0IHJhdGUgKG0ucy0xKSIpKwogIHRoZW1lX2pqbygpCmBgYAo=